package edu.neu.cs6515.admin;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.java.contract.Ensures;
import com.google.java.contract.Requires;

import edu.neu.cs6515.xml.IngeniousColor;
import edu.neu.cs6515.xml.Tile;

public class TileBag {

    private List<Tile> listOfTiles;

    @Requires("nbrOfTiles > 0")
    public TileBag(final int nbrOfTiles) {
        this(generateRandomTiles(
                nbrOfTiles));
    }

    @Requires("tiles!=null")
    public TileBag(final List<Tile> tiles) {
        this.listOfTiles = Lists.newLinkedList(tiles);
    }

    public int getNumberOfTiles() {
        return this.listOfTiles.size();
    }

    @Requires("getNumberOfTiles() > 0")
    @Ensures({ "result != null",
            "old(getNumberOfTiles()) == getNumberOfTiles() + 1" })
    public Tile drawATile() {
        return listOfTiles.remove(0);
    }

    @Requires("tile != null")
    @Ensures({ "old(getNumberOfTiles()) == getNumberOfTiles() - 1" })
    public void depositATile(final Tile tile) {
        this.listOfTiles.add(new Tile(tile.getC0(), tile.getC1()));
    }

    @Requires("tiles != null")
    @Ensures({ "old(getNumberOfTiles()) == getNumberOfTiles() - tiles.size()" })
    public void depositTiles(final List<Tile> tiles) {
        for (Tile tile : tiles) {
            this.depositATile(tile);
        }
    }

    @Requires("nbrOfTiles > 0 && nbrOfTiles <= getNumberOfTiles()")
    @Ensures({ "result != null && result.size() > 0",
            "old(getNumberOfTiles()) == getNumberOfTiles() + nbrOfTiles" })
    public List<Tile> drawTiles(final int nbrOfTiles) {
        List<Tile> tiles = new LinkedList<Tile>();
        for (int i = 0; i < nbrOfTiles; i++) {
            tiles.add(this.drawATile());
        }
        return tiles;
    }

    /**
     * @param numberOfTiles
     *            number of random tiles to be generated
     * @return a list containing "numberOfTiles" random tiles
     */
    private static List<Tile> generateRandomTiles(
            final int numberOfTiles) {
        Random rand = new Random();
        List<Tile> randomTiles =
                new LinkedList<Tile>();
        for (int i = 0; i < numberOfTiles; i++) {
            int colorIndex1 =
                    rand.nextInt(Administrator.NBR_OF_COLORS);
            int colorIndex2 =
                    rand.nextInt(Administrator.NBR_OF_COLORS);
            Tile randomTile =
                    new Tile(IngeniousColor.values()[colorIndex1],
                            IngeniousColor.values()[colorIndex2]);
            randomTiles.add(randomTile);
        }
        return randomTiles;
    }
}
